package org.gikolet.ch2.android;

import java.io.File;
import java.io.IOException;
import java.net.URL;

import org.apache.commons.io.FileUtils;
import org.gikolet.ch2.android.io.Ch2AndLocalDatReader;
import org.gikolet.ch2.android.io.Ch2ThreadHeadersReader;
import org.gikolet.ch2.android.io.LocalDatReader;
import org.gikolet.ch2.android.io.LocalKatjushaBoardsReader;
import org.gikolet.ch2.android.io.RemoteKatjushaBoardsReader;
import org.gikolet.ch2.data.Board;
import org.gikolet.ch2.data.ThreadHeader;
import org.gikolet.ch2.io.BoardsReader;
import org.gikolet.ch2.io.BoardsReaderProvider;
import org.gikolet.ch2.io.ReaderType;
import org.gikolet.ch2.io.ResesReader;
import org.gikolet.ch2.io.ResesReaderProvider;
import org.gikolet.ch2.io.Storage;
import org.gikolet.ch2.io.ThreadHeadersReader;
import org.gikolet.ch2.io.ThreadHeadersReaderProvider;
import org.gikolet.ch2.logic.AboneException;
import org.gikolet.ch2.logic.Ch2Exception;
import org.gikolet.ch2.logic.NotModifiedException;

import roboguice.inject.ContextScoped;
import android.os.Environment;

@ContextScoped
public class GikoletBbsProvider implements BoardsReaderProvider,
		ThreadHeadersReaderProvider, ResesReaderProvider, Storage {

	public GikoletBbsProvider() {
	}

	public BoardsReader createBoardsReader(ReaderType readerType)
			throws IOException {

		URL url = new URL("http://azlucky.s25.xrea.com/2chboard/2channel.brd");

		switch (readerType) {
		case CACHE:
			return new LocalKatjushaBoardsReader(getBoardFile(), "MS932");

		case CONNECT:
			return new RemoteKatjushaBoardsReader(url, false, this, "MS932");

		case CONNECT_CACHE:
			return new RemoteKatjushaBoardsReader(url, true, this, "MS932");
		}
		throw new IllegalStateException("BoardsReader is not found.");
	}

	public ThreadHeadersReader createThreadHeadersReader(Board board)
			throws IOException {
		return new Ch2ThreadHeadersReader(board);
	}

	public ResesReader createResesReader(ThreadHeader threadHeader,
			ReaderType readerType) throws NotModifiedException, AboneException,
			Ch2Exception, IOException {

		switch (readerType) {
		case CACHE:
			return new LocalDatReader(getThreadFile(threadHeader), "MS932");

		case CONNECT:
			threadHeader.setByteSize(null);
			threadHeader.setLastModified(null);
			return new Ch2AndLocalDatReader(threadHeader, this, "MS932");

		case CONNECT_CACHE:
			return new Ch2AndLocalDatReader(threadHeader, this, "MS932");
		}
		return null;
	}

	private File getDirectory(String path) {
		return new File(Environment.getExternalStorageDirectory(), "gikolet"
				+ File.separator + path);
	}

	public File getDirectoryAndCreate() throws IOException {
		return getDirectory("");
	}

	private File getLogsDirectory(String path) {
		return getDirectory("logs" + File.separator + path);
	}

	public File getBoardFile() {
		return getDirectory("2channel.brd");
	}

	public File getThreadFile(ThreadHeader th) {
		Board board = th.getBoard();

		return getLogsDirectory(board.getHostName() + File.separator
				+ board.getPath() + File.separator + th.getThreadKey() + ".dat");
	}

	public File getDirectory(Board board) throws IOException {

		return getLogsDirectory(board.getHostName() + File.separator
				+ board.getPath());
	}

	public File getDirectoryAndCreate(Board board) throws IOException {
		File file = getDirectory(board);

		// すでにディレクトリではなくファイルが存在する場合はここでエラーになるはず
		// そんなレアパターンを考慮する必要があるのか？
		// いつもありえないパターンを考え出して前へ進まない…
		FileUtils.forceMkdir(file);

		return file;
	}

	public File getTempDirectory() throws IOException {
		File tmp = new File("/tmp");

		if (!tmp.isDirectory()) {
			// メンドイ
			tmp = new File(Environment.getExternalStorageDirectory(),
					"gikolet/tmp");

			FileUtils.forceMkdir(tmp);
			if (tmp.mkdirs()) {
				throw new IllegalStateException("\"" + tmp
						+ "\" is not created.");
			}
		}
		return tmp;
	}
}
